if SUGAR_webber_the_trainer:getModConfigDataFromTUNING('_life') then
    local lang = STRINGS.MOD_WEBBER_THE_TRAINER.UI.life

    ---将本地数据挂到theplayer上
    ---@param inst ent
    local function webbert_refer_persistentstring(inst)
        if inst and inst._client_data_for_webbert_life == nil then
            ---@cast inst ent_player
            local stamp = inst.replica.webbert_life and inst.replica.webbert_life:GetTimeStamp()
            local file = 'webbert_life_start_at_'..stamp
            TheSim:GetPersistentString(file, function(load_success, data)
                if load_success and data ~= nil then
                    local status, _data = pcall( function() return json.decode(data) end )
                    if status and _data then
                        inst._client_data_for_webbert_life = _data
                    end
                end
            end)
        end
    end

    ---@type widget_widget
    local Widget = require 'widgets/widget'
    ---@type widget_image
    local Image = require 'widgets/image'
    ---@type widget_button
    local Button = require "widgets/button"
    ---@type widget_imagebutton
    local ImageButton = require 'widgets/imagebutton'
    ---@type widget_text
    local Text = require 'widgets/text'
    ---@type widget_textedit
    local TextEdit = require "widgets/textedit"
    ---@type widget_uianim
    local UIAnim = require "widgets/uianim"
    ---@type widget_playerbadge
    local PlayerBadge = require 'widgets/playerbadge'
    -- ---@type widget_scrollablelist
    -- local ScrollableList = require "widgets/scrollablelist"
    ---@type widget_scrollablelist
    local webbert_scrollablelist = require('core_webber_the_trainer/widgets/webbert_scrollablelist')

    ---------------------------------------------------------------
    ---构造生涯的单个玩家
    ---@class widget_webbert_life_panel_player : widget_widget
    ---@overload fun(prefab:string,displayname:string,userid:userid,fn:function):widget_webbert_life_panel_player
    ---@field bg widget_imagebutton
    ---@field bg_frame widget_image
    ---@field badge widget_playerbadge
    ---@field name widget_text
    ---@field userid userid
    local webbert_life_panel_player = Class(Widget,
    ---@param self widget_webbert_life_panel_player
    ---@param prefab string
    ---@param displayname string
    ---@param userid userid
    ---@param fn function
    function(self, prefab,displayname,userid, fn)
        Widget._ctor(self, 'webbert_life_panel_player')

        self.bg = self:AddChild(ImageButton('images/ui.xml', 'single_option_bg_large.tex', 'single_option_bg_large.tex', 'single_option_bg_large.tex', 'single_option_bg_large.tex', 'single_option_bg_large.tex'))
        self.bg.image:SetTint(.2,.2,.2,1)
        self.bg:SetFocusScale(1,1,1)
        self.bg_frame = self.bg:AddChild(Image('images/ui.xml', 'single_option_bg_large_white.tex', 'single_option_bg_large_white.tex'))
        self.bg_frame:SetClickable(false)
        self.bg_frame:Hide()
        self.bg:SetOnGainFocus(function()
            self.bg_frame:Show()
        end)
        self.bg:SetOnLoseFocus(function()
            self.bg_frame:Hide()
        end)
        self.bg:SetOnClick(function ()
            if fn ~= nil then
                fn()
            end
        end)

        self.bg:SetScale(.4,.55,1)
        self.bg:SetPosition(100,0,0)
        self.badge = self:AddChild(PlayerBadge(prefab,{1,.2,.2,1},false,0))
        self.badge:SetClickable(false)

        self.name = self:AddChild(Text(BODYTEXTFONT, 30, displayname or 'Player'))
        self.name:SetPosition(100,0,0)
        self.name:SetClickable(false)

        self.userid = userid
    end)

    ---------------------------------------------------------------
    ---生涯分类
    ---@class widget_webbert_life_class : widget_widget
    ---@overload fun(name:string,fn:fun()):widget_webbert_life_class
    ---@field btn widget_imagebutton
    ---@field name widget_text
    local webbert_life_class = Class(Widget,
    ---@param self widget_webbert_life_class
    ---@param name string
    ---@param fn fun()
    function(self,name,fn)
        Widget._ctor(self, 'webbert_life_class')
        local w,h = 300,60
        self.btn = self:AddChild(ImageButton('images/global_redux.xml','textbox3_gold_small_normal.tex','textbox3_gold_small_normal.tex','textbox3_gold_small_normal.tex','textbox3_gold_small_normal.tex','textbox3_gold_small_normal.tex'))
        self.btn:SetFocusScale(1,1,1)
        self.btn:SetImageNormalColour(238/255,192/255,110/255,1)
        self.btn:SetImageFocusColour(1,1,1,1)

        self.btn:SetScale(.6,.6,1)

        self.btn:SetOnClick(function ()
            if fn ~= nil then
                fn()
            end
        end)

        self.name = self:AddChild(Text(BODYTEXTFONT,30,name))
    end)

    ---------------------------------------------------------------
    ---@class webbert_life_work_kind_data
    ---@field scrapbookid string|nil
    ---@field txt_main string
    ---@field tex string|nil # 头像: 不用 scrapbookid 时, 用自定义的
    ---@field xml string|nil # 头像: 不用 scrapbookid 时, 用自定义的
    ---@field scale {[1]:number,[2]:number}|nil # 头像: 自定义缩放
    ---@field need_bg boolean|nil # 头像: 是否需要一个预设的背景

    ---@type table<webbert_life_work_kind,webbert_life_work_kind_data>
    local work_kind_data = {
        chopdone = {
            scrapbookid = 'evergreen_tall',
            txt_main = lang.chopdone,
        },
        minedone = {
            scrapbookid = 'rock2',
            txt_main  = lang.minedone,
        },
        fish = {
            tex = 'fish.tex',
            xml = GetInventoryItemAtlas('fish.tex'),
            -- scale = {1,1},
            need_bg = true,
            txt_main = lang.fish,
        },
        honey = {
            scrapbookid = 'beebox',
            txt_main = lang.honey,
        },
        craft = {
            tex = 'station_none.tex',
            xml = 'images/crafting_menu_icons.xml',
            scale = {.16,.16},
            txt_main = lang.craft,
            need_bg = true,
        },
        bigplant = {
            tex = 'garlic_oversized.tex',
            xml = GetInventoryItemAtlas('garlic_oversized.tex'),
            scale = {.7,.7},
            need_bg = true,
            txt_main = lang.bigplant
        },
        dish = {
            scrapbookid = 'cookpot',
            txt_main = lang.dish,
        },
        dig = {
            tex = 'goldenshovel.tex',
            xml = GetInventoryItemAtlas('goldenshovel.tex'),
            scale = {.57,.57},
            need_bg = true,
            txt_main = lang.dig,
        },
        till = {
            tex = 'golden_farm_hoe.tex',
            xml = GetInventoryItemAtlas('golden_farm_hoe.tex'),
            scale = {.57,.57},
            need_bg = true,
            txt_main = lang.till,
        },
        hammer = {
            tex = 'hammer.tex',
            xml = GetInventoryItemAtlas('hammer.tex'),
            scale = {.57,.57},
            need_bg = true,
            txt_main = lang.hammer,
        },
        net = {
            tex = 'bugnet.tex',
            xml = GetInventoryItemAtlas('bugnet.tex'),
            scale = {.57,.57},
            need_bg = true,
            txt_main = lang.net,
        },
        td_pigking = {
            scrapbookid = 'pigking',
            txt_main = lang.td_pigking,
        },
        td_bird = {
            scrapbookid = 'birdcage',
            txt_main = lang.td_bird,
        },
        td_antlion = {
            scrapbookid = 'antlion',
            txt_main = lang.td_antlion,
        },
        farmplant = {
            scrapbookid = 'farm_plant_randomseed',
            txt_main = lang.farmplant,
        },
    }

    ---生涯统计分类条目
    ---@class webbert_life_class_data
    ---@field name string # 分类名称
    ---@field fn fun(key:string,num:number,other:table|nil):(boolean,table|nil) # 成员参数创建函数

    ---@type table<string,webbert_life_class_data>
    local classes = {
        kill = {
            name = lang.class_kill,
            fn = function(key,num,other)
                local tex = key..'.tex'
                local xml = GetScrapbookIconAtlas(tex)
                if xml then
                    local sub_s = lang.sup_kill_hint .. tostring(other and other[key] or 0)
                    return true,{{xml = xml, tex = tex, scale = {.4,.4}},STRINGS.NAMES[string.upper(key)],lang.kill_hint.. num,sub_s,false}
                end
                return false,nil
            end
        },
        work = {
            name = lang.class_work,
            fn = function (key, num, other)
                ---@cast key webbert_life_work_kind
                local _data = work_kind_data[key]
                local tex = _data.tex or (_data.scrapbookid and (_data.scrapbookid..'.tex')) or nil
                local xml = _data.xml or (tex and GetScrapbookIconAtlas(tex)) or nil
                local need_bg = _data.need_bg and true or false
                local scale = _data.scale or {.4,.4}
                local res = {tex and {xml = xml, tex = tex, scale = scale},nil,_data.txt_main..num,'',need_bg}
                return true,res
            end
        },
        eat = {
            name = lang.class_eat,
            fn = function (key, num, other)
                local tex = key..'.tex'
                local xml = GetInventoryItemAtlas(tex,true)
                if xml then
                    return true,{{xml = xml, tex = tex, scale = {.57,.57}},STRINGS.NAMES[string.upper(key)],lang.eat_hint..num,'',true}
                end
                return false,nil
            end
        },
        wp = {
            name = lang.class_wp,
            fn = function (key, num, other)
                local tex = key..'.tex'
                local xml = GetInventoryItemAtlas(tex,true)
                if xml then
                    return true,{{xml = xml, tex = tex, scale = {.57,.57}},STRINGS.NAMES[string.upper(key)],lang.wp_hint..num,'',true}
                end
                return false,nil
            end
        },
    }

    local order_classes = {
        'kill',
        'work',
        'eat',
        'wp',
    }


    ---------------------------------------------------------------
    ---生涯单个条目
    ---@class widget_webbert_life_item : widget_widget
    ---@overload fun(img_data:{xml:string,tex:string,scale:{[1]:number,[2]:number}|nil}|nil,hint:string|nil,txt_main:string,txt_sub:string|nil,need_bg:boolean|nil)
    ---@field avatar widget_image # 图片, 可以没有
    ---@field avatar_bg widget_image # 图片背景, 可以没有
    ---@field bg widget_image # 背景
    ---@field hint widget_text # 聚焦条目的提示
    ---@field info_main widget_text # 主要信息 必须要有
    ---@field info_sub widget_text # 次要信息 当次要信息存在时, 与主要信息分上下两行显示,否则主要信息居中显示
    local webbert_life_item = Class(Widget,
    ---@param self widget_webbert_life_item
    ---@param img_data {xml:string,tex:string,scale:{[1]:number,[2]:number}|nil}|nil # 
    ---@param hint string|nil
    ---@param txt_main string
    ---@param txt_sub string|nil
    ---@param need_bg boolean|nil
    function(self,img_data,hint,txt_main,txt_sub,need_bg)
        Widget._ctor(self, 'webbert_life_item')

        local w,h = 380,60
        self.bg = self:AddChild(Image('images/global_redux.xml', 'spinner_background_normal.tex', 'spinner_background_normal.tex'))
        self.bg:SetSize(w,h)
        self.bg:SetPosition(w/2-40,0)
        if need_bg then
            self.avatar_bg = self:AddChild(Image('images/ui.xml', 'portrait_bg.tex', 'portrait_bg.tex'))
            self.avatar_bg:SetClickable(false)
            -- 如果使用预设背景 那么缩放一下
            self.avatar_bg:SetScale(.39,.39)
        end
        if img_data then
            self.avatar = self:AddChild(Image(img_data.xml,img_data.tex,img_data.tex))
            self.avatar:SetClickable(false)
            local scale = img_data.scale
            if scale then
                self.avatar:SetScale(scale[1],scale[2])
            end
        end
        if hint then
            self.hint = self:AddChild(Text(BODYTEXTFONT,30,hint))
            self.hint:Hide()
            self.hint:SetPosition(0,30)
            self.bg:SetOnGainFocus(function()
                self.hint:Show()
            end)
            self.bg:SetOnLoseFocus(function()
                self.hint:Hide()
            end)
        end
        local x,y = 150,10
        if txt_sub and txt_sub ~= '' then
            self.info_main = self:AddChild(Text(BODYTEXTFONT,23,txt_main))
            self.info_main:SetPosition(x,y)
            self.info_main:SetRegionSize(240,24)
            self.info_main:SetHAlign(ANCHOR_LEFT)

            self.info_sub = self:AddChild(Text(BODYTEXTFONT,23,txt_sub))
            self.info_sub:SetPosition(x,-y)
            self.info_sub:SetRegionSize(240,24)
            self.info_sub:SetHAlign(ANCHOR_LEFT)
        else
            self.info_main = self:AddChild(Text(BODYTEXTFONT,30,txt_main))
            self.info_main:SetPosition(x,0)
            self.info_main:SetRegionSize(240,32)
            self.info_main:SetHAlign(ANCHOR_LEFT)
        end
    end)


    ---------------------------------------------------------------
    ---生涯主面板
    ---@class widget_webbert_life_panel : widget_widget
    ---@field root widget_widget
    ---@field bg widget_image # 生涯bg
    ---@field title_bg widget_image # 生涯标题bg
    ---@field title widget_text # 生涯标题
    ---@field scrollablelist_player widget_scrollablelist
    ---@field scrollablelist_player_item widget_webbert_life_panel_player[]
    ---@field scrollablelist_class widget_scrollablelist
    ---@field scrollablelist_class_item widget_webbert_life_class[]
    ---@field scrollablelist_detail widget_scrollablelist
    ---@field scrollablelist_detail_item widget_webbert_life_item[]
    ---@field is_checking_which_player userid # 正在检查哪个玩家的生涯
    local webbert_life_panel = Class(Widget,
    ---@param self widget_webbert_life_panel
    function(self)
        Widget._ctor(self, 'webbert_life_panel')

        -- root
        self.root = self:AddChild(Widget('root'))
        self.root:SetVAnchor(ANCHOR_MIDDLE)
        self.root:SetHAnchor(ANCHOR_MIDDLE)
        self.root:SetScaleMode(SCALEMODE_FIXEDPROPORTIONAL)
        self.root:SetMaxPropUpscale(.75)

        self.bg = self.root:AddChild(Image('images/quagmire_recipebook.xml', 'quagmire_recipe_menu_bg.tex', 'quagmire_recipe_menu_bg.tex'))
        self.bg:SetScale(.7,.7,1)

        self.title_bg = self.root:AddChild(Image('images/ui.xml','update_banner.tex','update_banner.tex'))
        self.title_bg:SetPosition(0,290)

        self.title = self.title_bg:AddChild(Text(BODYTEXTFONT,30,STRINGS.MOD_WEBBER_THE_TRAINER.UI.life.life))
        self.title:SetPosition(0,10)

        self:_createPlayerList()
        self:_createClassList()

        self.is_checking_which_player = ThePlayer and ThePlayer.userid or nil
        -- local tex = 'deerclops'..'.tex'
        -- local xml = GetScrapbookIconAtlas(tex)
        -- if tex and xml then
        --     self.p = self.root:AddChild(webbert_life_item({xml = xml, tex = tex, scale = {.4,.4}},'巨鹿','击杀: 12322222222222222222222222222222222222222222222222222222'))
        -- end

    end)

    ---设置生涯标题, 不填则设置回旧标题
    ---@param displayname string # 不填则设置回旧标题
    function webbert_life_panel:SetJourneyTitle(displayname)
        local title = displayname and subfmt(STRINGS.MOD_WEBBER_THE_TRAINER.UI.life.whoslife,{player = displayname or 'Player'}) or STRINGS.MOD_WEBBER_THE_TRAINER.UI.life.life
        self.title:SetString(title)
    end

    ---创建单个玩家
    ---@param prefab string
    ---@param displayname string
    ---@param userid userid
    ---@param fn function
    ---@return widget_webbert_life_panel_player
    function webbert_life_panel:_createSinglePLayer(prefab,displayname,userid,fn)
        return webbert_life_panel_player(prefab,displayname,userid,function ()
            self:SetJourneyTitle(displayname)
            if fn then
                fn()
            end
        end)
    end

    ---创建玩家滚动条
    function webbert_life_panel:_createPlayerList()
        for k,v in pairs(self.scrollablelist_player_item or {}) do
            v:Kill()
        end
        self.scrollablelist_player_item = nil
        self.scrollablelist_player_item = {}
        if self.scrollablelist_player then
            self.scrollablelist_player:Kill()
            self.scrollablelist_player = nil
        end

        ---@class ThePlayer
        ---@field _client_webbert_life_player_map table<userid,{prefab:string,displayname:string}> # 用于临时存储玩家信息

        if ThePlayer._client_webbert_life_player_map == nil then
            ThePlayer._client_webbert_life_player_map = {}
        end
        -- 记录哪些玩家已经生成过
        local map_userid = {}
        -- 先生成临时列表
        for k, v in pairs(ThePlayer._client_webbert_life_player_map) do
            local member = self:_createSinglePLayer(v.prefab,v.displayname,k,function ()
                self.is_checking_which_player = k
            end)
            member:SetScale(.7,.7)
            table.insert(self.scrollablelist_player_item, member)
            map_userid[k] = true
        end
        -- 再遍历现有玩家列表
        for _,v in ipairs(AllPlayers or {}) do
            local prefab = v.prefab
            local displayname = v:GetDisplayName()
            local userid = v.userid
            if userid and not map_userid[userid] then
                local member = self:_createSinglePLayer(prefab,displayname,userid,function ()
                    self.is_checking_which_player = userid
                end)

                member:SetScale(.7,.7)
                table.insert(self.scrollablelist_player_item, member)
                map_userid[userid] = true
            end
        end


        self.scrollablelist_player = self.root:AddChild(webbert_scrollablelist(self.scrollablelist_player_item, 160, 410, 55, 4, nil, nil, 0, nil, nil, nil, nil, nil,'webbert_style'))
        self.scrollablelist_player:SetPosition(-300,0,0)
        self.scrollablelist_player.scroll_bar_line:SetScale(.8,1,1)


    end

    ---创建单个类型
    ---@param name any
    ---@param fn function
    ---@return widget_webbert_life_class
    function webbert_life_panel:_createSingleClass(name,fn)
        return webbert_life_class(name,fn)
    end

    ---创建类型滚动条
    function webbert_life_panel:_createClassList()
        for k,v in pairs(self.scrollablelist_class_item or {}) do
            v:Kill()
        end
        self.scrollablelist_class_item = nil
        self.scrollablelist_class_item = {}
        if self.scrollablelist_class then
            self.scrollablelist_class:Kill()
            self.scrollablelist_class = nil
        end
        -- 重新生成
        for _,v in ipairs(order_classes) do
            local member_data = classes[v]
            if member_data then
                local member = self:_createSingleClass(member_data.name,function ()
                    self:_createItemList(v)
                end)
                member:SetScale(.7,.7)
                table.insert(self.scrollablelist_class_item, member)
            end
        end
        self.scrollablelist_class = self.root:AddChild(webbert_scrollablelist(self.scrollablelist_class_item, 80, 410, 30, 9, nil, nil, 0, nil, nil, nil, nil, nil,'webbert_style'))
        self.scrollablelist_class:SetPosition(-90,0,0)
        self.scrollablelist_class.scroll_bar_line:SetScale(.8,1,1)
    end

    ---生成类型对应的物品列表
    ---@param which_class string|nil # 不填则清空
    function webbert_life_panel:_createItemList(which_class)
        -- 先清空
        for _,_v in pairs(self.scrollablelist_detail_item or {}) do
            _v:Kill()
        end
        self.scrollablelist_detail_item = nil
        self.scrollablelist_detail_item = {}
        if self.scrollablelist_detail then
            self.scrollablelist_detail:Kill()
            self.scrollablelist_detail = nil
        end
        -- 生成类型对应的物品列表
        if which_class and self.is_checking_which_player then -- 检测当前正在看哪个玩家, 默认自己
            -- 如果还没有加载过本地数据 那么先加载
            webbert_refer_persistentstring(ThePlayer)
            -- 加载好了之后
            if ThePlayer._client_data_for_webbert_life then
                local page_kill = ThePlayer._client_data_for_webbert_life[self.is_checking_which_player] and ThePlayer._client_data_for_webbert_life[self.is_checking_which_player][which_class]
                local gen_params_fn = classes[which_class].fn
                if page_kill and gen_params_fn then
                    local map = {} -- 临时表
                    -- 临时表 以便排序
                    local sorted_list = {}
                    for key, num in pairs(page_kill) do
                        table.insert(sorted_list, {key = key, num = num})
                        map[key] = true
                    end
                    -- 降序
                    table.sort(sorted_list, function(a, b)
                        return a.num > b.num
                    end)
                    -- 获取下助攻表
                    local sup_kill = ThePlayer._client_data_for_webbert_life[self.is_checking_which_player].sup_kill or nil
                    -- 如果是击杀表,则把助攻也插进去
                    if which_class == 'kill' and sup_kill then
                        for k,_ in pairs(sup_kill) do
                            if not map[k] then
                                map[k] = true
                                table.insert(sorted_list, {key = k, num = 0})
                            end
                        end
                    end
                    for _,item in pairs(sorted_list) do
                        local success, tbl = gen_params_fn(item.key,item.num,sup_kill)
                        if success and tbl then
                            local single_item_widget = webbert_life_item(unpack(tbl))
                            table.insert(self.scrollablelist_detail_item,single_item_widget)
                        end
                    end
                end
                self.scrollablelist_detail = self.root:AddChild(webbert_scrollablelist(self.scrollablelist_detail_item, 360, 410, 55, 4, nil, nil, 0, nil, nil, nil, nil, nil,'webbert_style'))
                self.scrollablelist_detail:SetPosition(190,0,0)
                self.scrollablelist_detail.scroll_bar_line:SetScale(.8,1,1)
            end
        end
    end

    function webbert_life_panel:ReBuildLife()
        self:_createPlayerList()
        self:_createItemList(nil)
    end

    return webbert_life_panel
end
